﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using QuadRemote.Core;


namespace QuadRemote.Tabs
{
    public partial class ConnectionPanel : UserControl
    {
        Timer statusTimer;

        public ConnectionPanel()
        {
            InitializeComponent();
            statusTimer = new Timer();
            statusTimer.Interval = 100;
            statusTimer.Tick += new EventHandler(this.btStatus);
        }

        private void ConnectionPanel_Load(object sender, EventArgs e)
        {
            cbPort.Items.Clear();

            string[] ports = SerialPort.GetPortNames();
            foreach (string p in ports)
            {
                cbPort.Items.Add(p);
                if (Properties.Settings.Default.BTPort == p)
                {
                    cbPort.SelectedIndex = cbPort.Items.Count - 1;
                }
            }

            statusTimer.Enabled = true;
        }

        private void btConnect_Click(object sender, EventArgs e)
        {
            if (Core.Bluetooth.instance().Connect)
            {
                Core.Bluetooth.instance().Connect = false;
                cbPort.Enabled = true;
                btConnect.Text = "Connect";
            }
            else
            {
                if (((string)cbPort.SelectedItem.ToString()) != Properties.Settings.Default.BTPort)
                {
                    Properties.Settings.Default.BTPort = (String)cbPort.SelectedItem.ToString();
                    Properties.Settings.Default.Save();
                }

                Core.Bluetooth.instance().Connect = true;
                cbPort.Enabled = false;
                btConnect.Text = "Disconnect";
            }
        }


        private long[] receivedBytes = new long[11];
        private long[] receivedPayload = new long[11];
        private long[] receivedPackets = new long[11];
        //private long[] receivedBytesDouble = new long[11];
        private long receivedSkipped = 0;
        private long maxReceived = 0;

        private long[] sentBytes = new long[11];
        private long[] sentPayload = new long[11];
        private long[] sentPackets = new long[11];
        //private long[] sentBytesDouble = new long[11];
        private long resent = 0;
        private long maxSent = 0;

        private int index = 1;

        public String getSpeed(long speed, Boolean isSpeed)
        {
            if (speed < 1024) return speed + (isSpeed ? "bps" : "b");
            else if (speed < 1024 * 1024) return Math.Round((double)speed / 1024, 1) + (isSpeed ? "kbps" : "kb");
            else return Math.Round((double)speed / 1024 / 1024, 1) + (isSpeed ? "mbps" : "mb");
        }

        public void btStatus(object Sender, EventArgs args)
        {
            int state = Core.Bluetooth.instance().state;

            if (state == Core.Bluetooth.STATE_CONNECTED) lblStatus.Text = "Connected (...)";
            else if (state == Core.Bluetooth.STATE_CONNECTED_STABLE) lblStatus.Text = "Connected";
            else if (state == Core.Bluetooth.STATE_CONNECTING) lblStatus.Text = "Connecting...";
            else if (state == Core.Bluetooth.STATE_CONNECTING_FAILED) lblStatus.Text = "Connecting failed";
            else if (state == Core.Bluetooth.STATE_CONTROL_TIMEOUT) lblStatus.Text = "Connection dropped";
            else if (state == Core.Bluetooth.STATE_DISCONNECTED) lblStatus.Text = "Disconnected";


            index++;
            if (index == 11) index = 1;

            Core.Bluetooth bt = Core.Bluetooth.instance();
            receivedBytes[index] = bt.bytesReceived - receivedBytes[0];
            receivedPackets[index] = bt.packetsReceived - receivedPackets[0];
            receivedPayload[index] = bt.bytesReceivedPayload - receivedPayload[0];
            receivedSkipped = bt.bytesReceivedSkipped;
            
            sentBytes[index] = bt.bytesSent - sentBytes[0];
            sentPayload[index] = bt.bytesSentPayload - sentPayload[0];
            sentPackets[index] = bt.packetsSent - sentPackets[0];
            resent = bt.bytesResent;

            int sum1, sum2, sum3;

            sum1 = 0; sum2 = 0; sum3 = 0;
            for (int i = 1; i < 11; i++)
            {
                sum1 += (int)receivedBytes[i];
                sum2 += (int)receivedPayload[i];
                sum3 += (int)receivedPackets[i];
            }

            if (sum1 > maxReceived) maxReceived = sum1;

            pgReceived.Value = sum1 > pgReceived.Maximum ? pgReceived.Maximum : sum1;
            lblReceived.Text = "Speed: " + getSpeed(sum1, true) +
                "     Overhead: " + (sum1 != 0 ? Math.Round((double)(sum1 - sum2) / sum1 * 100, 0) : 0) + "%" +
                "     Total bandwidth: " + getSpeed(receivedBytes[0], false) +
                "     Max speed: " + getSpeed(maxReceived,true) +
                "     Packets: " + sum3 +
                "     Total packets: " + receivedPackets[0] +
                "     Skipped bytes: " + getSpeed(receivedSkipped, false);

            sum1 = 0; sum2 = 0; sum3 = 0;
            for (int i = 1; i < 11; i++)
            {
                sum1 += (int)sentBytes[i];
                sum2 += (int)sentPayload[i];
                sum3 += (int)sentPackets[i];
            }

            if (sum1 > maxSent) maxSent = sum1;
            pgSent.Value = sum1 > pgSent.Maximum ? pgSent.Maximum : sum1;
            lblSent.Text = "Speed: " + getSpeed(sum1, true) +
                "     Overhead: " + (sum1 != 0 ? Math.Round((double)(sum1 - sum2) / sum1 * 100, 0) : 0) + "%" +
                "     Total bandwidth: " + getSpeed(sentBytes[0], false) +
                "     Max speed: " + getSpeed(maxSent, true) +
                "     Packets: " + sum3 +
                "     Total packets: " + sentPackets[0] +
                "     Resent bytes: " + getSpeed(resent, false);



            receivedBytes[0] = bt.bytesReceived;
            receivedPackets[0] = bt.packetsReceived;
            receivedPayload[0] = bt.bytesReceivedPayload;
            sentBytes[0] = bt.bytesSent;
            sentPayload[0] = bt.bytesReceivedPayload;
            sentPackets[0] = bt.packetsSent;


            /*
            //if (counter++ < 10) return;
            counter = 0;
            long t = Core.Bluetooth.instance().bytesSent;
            bytesSent[graphIndex] = t - lastBytesSent;
            lastBytesSent = t;

            t = Core.Bluetooth.instance().bytesReceived;
            bytesReceived[graphIndex] = t - lastBytesReceived;
            lastBytesReceived = t;

            t = Core.Bluetooth.instance().bytesResent;
            bytesResent[graphIndex] = t - lastBytesResent;
            lastBytesResent = t;

            float s = 0;
            float r = 0;
            float rr = 0;

            int j = graphIndex;
            for (int i = 0; i < 1000; i += statusTimer.Interval)
            {
                s += bytesSent[j];
                r += bytesReceived[j];
                rr += bytesResent[j];
                j--;
                if (j < 0) j = bytesSent.Length - 1;
            }

            graphIndex++;
            if (graphIndex >= bytesSent.Length)
            {
                graphIndex = 0;
            }

            string sm = "TX: ";
            if (s < 512) sm += Math.Round(s) + "B/s";
            else sm += Math.Round(s / 102.4f) / 10 + "KB/s";

            sm += "    RX: ";
            if (r < 512) sm += Math.Round(r) + "B/s";
            else sm += Math.Round(r / 102.4f) / 10 + "KB/s";

            sm += "    Resent: ";
            if (rr < 512) sm += Math.Round(rr) + "B/s";
            else sm += Math.Round(rr / 102.4f) / 10 + "KB/s";

            portSpeed.Text = sm;
            */
//            this.Invalidate();
        }

        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

        private void groupBox2_Enter(object sender, EventArgs e)
        {

        }

        private void groupBox2_Enter_1(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            FlightSession.current().resetLogs();
        }

        private void groupBox1_Enter(object sender, EventArgs e)
        {

        }

        private void button3_Click(object sender, EventArgs e)
        {

        }

    }
}
